package movee.os;

import java.io.IOException;

/**
 * 安全执行os命令
 */
public class SafeExec {

    private static Platform platform;

    public static enum Platform {
        WINDOWS,
        UNIX
    }

    static {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.startsWith("win")) {
            platform = Platform.WINDOWS;
        } else {
            platform = Platform.UNIX;
        }
    }

    public static Process execute(String[][] cmdArray)
            throws IOException, SecurityException, IllegalArgumentException {
        return execute(cmdArray, false);
    }

    public static Process execute(String[][] cmdArray, boolean strictMode)
            throws IOException, SecurityException, IllegalArgumentException {
        checkCmdArray(cmdArray);
        String[] formattedCmd = formatParams(cmdArray, strictMode);
        return Runtime.getRuntime().exec(formattedCmd);
    }

    private static void checkCmdArray(String[][] cmdArray) throws IllegalArgumentException {
        if (cmdArray == null) {
            throw new IllegalArgumentException("cmdArray is null");
        }
        if (cmdArray.length == 0) {
            throw new IllegalArgumentException("cmdArray is empty");
        }
    }

    private static void checkCmdParam(String[] cmdParam) throws IllegalArgumentException {
        if (cmdParam == null) {
            throw new IllegalArgumentException("cmdArray item is null");
        }
        if (cmdParam.length == 0) {
            throw new IllegalArgumentException("cmdArray item is empty");
        }
    }

    private static String[] formatParams(String[][] cmd, boolean strctMode)
            throws IllegalArgumentException {
        String[] formattedCmd = new String[cmd.length];
        if (platform == Platform.WINDOWS) {
            for (int i = 0; i < cmd.length; i++) {
                checkCmdParam(cmd[i]);
                if (cmd[i].length == 1) {
                    formattedCmd[i] = cmd[i][0];
                } else {
                    String[] formattedParams = new String[cmd[i].length - 1];
                    for (int j = 1; j < cmd[i].length; j++) {
                        formattedParams[j - 1] = formatWindowsParam(cmd[i][j]);
                    }
                    try {
                        formattedCmd[i] = String.format(cmd[i][0], formattedParams);
                    } catch (Exception e) {
                        throw new IllegalArgumentException("format cmdArray error", e);
                    }
                }
            }
        } else if (platform == Platform.UNIX) {
            for (int i = 0; i < cmd.length; i++) {
                checkCmdParam(cmd[i]);
                if (cmd[i].length == 1) {
                    formattedCmd[i] = cmd[i][0];
                } else {
                    String[] formattedParams = new String[cmd[i].length - 1];
                    for (int j = 1; j < cmd[i].length; j++) {
                        formattedParams[j - 1] = formatUnixParam(cmd[i][j], strctMode);
                    }
                    try {
                        formattedCmd[i] = String.format(cmd[i][0], formattedParams);
                    } catch (Exception e) {
                        throw new IllegalArgumentException("format cmdArray error", e);
                    }
                }
            }
        }
        return formattedCmd;
    }

    private static String formatUnixParam(String param, boolean strictMode) {
        if (param == null) {
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder();

        // 去除前置“-”
        if (strictMode) {
            param = param.replaceFirst("^-+", "");
        }

        // 两侧添加单引号
        stringBuilder.append("'");
        for (int i = 0; i < param.length(); i++) {
            // 单引号转义，单引号分隔的前后两部分字符串添加单引号
            if (param.charAt(i) == '\'') {
                stringBuilder.append("'\\''");
            } else {
                stringBuilder.append(param.charAt(i));
            }
        }
        // 两侧添加单引号
        stringBuilder.append("'");
        return stringBuilder.toString();
    }

    private static String formatWindowsParam(String param) {
        if (param == null) {
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < param.length(); i++) {
            char c = param.charAt(i);
            // 非英文字母和数字的字符，前置“^”转义
            if (!Character.isLetterOrDigit(c)) {
                stringBuilder.append('^');
            }
            stringBuilder.append(c);
        }
        return stringBuilder.toString();
    }

}
